﻿#region Using directives

using System;
using System.Collections.Generic;
using System.Windows.Forms;

#endregion
using System.IO;
using Thinxoft.HttpLib;
using System.Threading;
using System.Runtime.Remoting.Channels;
using System.Runtime.Remoting.Channels.Ipc;
using System.Runtime.Remoting;
using System.Runtime.Remoting.Lifetime;
using System.Collections.Specialized;
using System.Text;


namespace HTTPReqMan
{
    


    public static class Monitor
    {

        static Dictionary<string, Dictionary<string, HttpResource>> resources = new Dictionary<string, Dictionary<string, HttpResource>>();
       
        
        
        static Dictionary<string, FileSystemWatcher> monitors;

        public static Dictionary<string, Dictionary<string, HttpResource>> Resources
        {
            get
            {
                return resources;
            }
        }

       

        public static byte[] GetResource(HttpResource httpResource, string query, string resource,ref NameValueCollection headers,ref NameValueCollection postparams)
        {           
            
            if (httpResource != null)
            {
                if (httpResource.ResourceType == "http")
                {
                    HttpRequest req = new HttpRequest(ref headers, ref postparams, ref httpResource);
                    req.ProcessRequest(query);
                    HttpResponse resp = req.CreateResponse();
                    return (byte[])resp;
                }
                else
                {
                    DefaultResource dres = (DefaultResource) httpResource;
                    StringBuilder sb = new StringBuilder("<html><head></head><body>");
                    foreach (HttpResource child in dres.Children)
                    {
                        sb.AppendFormat("<a href=\"{0}\"></a>",child.Offset);
                    }
                    sb.AppendFormat("</body></html>");
                    return HttpResponse.WriteHTMLResponse(sb.ToString(),HttpResponse.ResponseCode.Ok);
                }
            }
            else
            {
                return HttpResponse.WriteResponse("Could not find resource " + resource, HttpResponse.ResponseCode.Ok);
            }
        }

        static HttpResource GetResource(ref HttpApplication app, string resourceKey, ref Dictionary<string, HttpResource> resourceList)
        {

            if (resourceKey == app.Name + ":/")
            {
                //search for a default document to serve as the resource
                foreach (string doc in app.DefaultDocuments)
                {
                    resourceKey = app.Name + ":" + doc;
                    if (resourceList.ContainsKey(resourceKey))
                    {
                        HttpResource rs = resourceList[resourceKey];
                        if (rs.IsXFile)
                        {
                            string assembly = "xfiles/" + rs.FileNameWithoutExtension + ".dll";
                            if (!File.Exists(assembly))
                            {
                                XFileCompiler.Run(rs);
                            }
                        }
                        return rs;
                    }
                }
            }
            else
            {               
                if (resourceList.ContainsKey(resourceKey))
                {
                    HttpResource rs = resourceList[resourceKey];
                    return rs;
                }
                else
                    return null;
                
                
            }
            return null;
        }

        [STAThread]
        public static void StartMonitor(ServerState xstate)
        {

            
            try
            {
               
                monitors = new Dictionary<string, FileSystemWatcher>();
               

                foreach (HttpApplication app in xstate.Applications)
                {
                    
                    //create resourcelist for application
                    resources.Add(app.Name, new Dictionary<string, HttpResource>());

                    DefaultResource dres = new DefaultResource(app.DocumentRoot, app);
                    resources[app.Name].Add(dres.Offset, dres);
                    LoadResources(app.DocumentRoot, app, dres);

                    if (!File.Exists(app.DocumentRoot))
                        Directory.CreateDirectory(app.DocumentRoot);

                    FileSystemWatcher modMonitor = new FileSystemWatcher(app.DocumentRoot, "*.*");
                    
                    
                    modMonitor.NotifyFilter = NotifyFilters.Attributes | NotifyFilters.CreationTime
                        | NotifyFilters.LastAccess | NotifyFilters.Security | NotifyFilters.Size
                        | NotifyFilters.LastWrite | NotifyFilters.FileName | NotifyFilters.DirectoryName;
                    modMonitor.IncludeSubdirectories = true;

                    //update cache with changes to file by deleting resource
                    modMonitor.Changed += delegate(object sender, FileSystemEventArgs e)
                    {
                        UpdateCache(app, e);
                    };
                    modMonitor.Created += delegate(object sender, FileSystemEventArgs e)
                    {
                        UpdateCache(app, e);
                    };

                    modMonitor.Deleted += delegate(object sender, FileSystemEventArgs e)
                    {
                        UpdateCache(app, e);
                    };

                    modMonitor.Renamed += delegate(object sender, RenamedEventArgs e)
                    {
                        HttpResource res = new HttpResource(e.OldFullPath,app);
                        resources[app.Name].Remove(res.Offset);
                        UpdateCache(app, e);

                    };

                    modMonitor.EnableRaisingEvents = true;
                    monitors.Add(app.Name, modMonitor);
                }

            }
            catch (Exception ex)
            {
                ServerState.Log("In HttpModMonitor-[{0}]:{1}", ex.Message, ex.StackTrace);
            }
        }

        

        static void UpdateCache(HttpApplication hostapp, FileSystemEventArgs e)
        {
            try
            {
                string fileType = Path.GetExtension(e.FullPath);
                string file = e.FullPath;
                switch (fileType)
                {
                    case ".x":
                        {

                            //remove all app domains associated with the resource
                            HttpResource res = new HttpResource(e.FullPath,ref hostapp);
                            Dictionary<string, HttpResource> resourceList = resources[hostapp.Name];
                            if (resourceList.ContainsKey(res.Offset))
                            {
                                HttpResource oldres = resourceList[res.Offset];
                                //HttpResource oldres = Monitor.GetResource(ref hostapp, res.Offset, ref resourceList);
                                oldres.Dispose();
                            }

                            //get rid of old dll
                            string dll = HttpApplication.XFile_BIN + Path.GetFileNameWithoutExtension(file) + ".dll";
                            File.Delete(dll);


                            LoadSingleResource(file, hostapp);

                            break;
                        }
                    case ".dll":
                        break;
                    default:
                        {
                            //get moniker to old name                   
                            HttpResource res = new HttpResource(e.FullPath,ref hostapp);
                            //resources[hostapp.Name].Remove(res.Offset);  //remove from list
                            LoadSingleResource(file, hostapp);
                            //load new name
                            //LoadResources(e.FullPath, hostapp);
                            break;
                        }
                }
            }
            catch (Exception ex)
            {

            }
        }

        internal static HttpResource LoadSingleResource(string path, HttpApplication hostapp)
        {          
            HttpResource res = new HttpResource(path,ref hostapp);
            if (res.Exists)
            {
                if (res.IsXFile)
                {
                    XFileCompiler.Run(res, true);
                }
                else
                {
                    res.Serialize();
                }
                
                if (resources[hostapp.Name].ContainsKey(res.Offset))
                {
                    resources[hostapp.Name].Remove(res.Offset);  //remove old resource
                    resources[hostapp.Name].Add(res.Offset, res);  //add new resource
                }else
                    resources[hostapp.Name].Add(res.Offset, res);
                return res;
            }

            return null;

           
        }

        static void LoadResources(string path, HttpApplication hostapp, DefaultResource root)
        {
            if (Directory.Exists(path))
            {
                
                foreach (string directory in Directory.GetDirectories(path))
                {
                    DefaultResource res = new DefaultResource(directory, ref hostapp);
                    resources[hostapp.Name].Add(res.Offset, res);
                    LoadResources(directory, hostapp,res);
                    root.Children.Add(res);
                }


                foreach (string file in Directory.GetFiles(path))
                {
                    HttpResource res = new HttpResource(file,ref hostapp);

                    if (resources[hostapp.Name].ContainsKey(res.Offset))
                    {
                    }
                    else
                    {
                        
                        if (res.IsXFile)
                        {
                            XFileCompiler.Run(res, true);
                        }
                        else
                        {
                            res.Serialize();
                        }
                        resources[hostapp.Name].Add(res.Offset, res);
                    }
                    root.Children.Add(res);
                }

            }
            else
            {
                HttpResource res = new HttpResource(path,ref hostapp);
                if (res.IsXFile)
                {
                    XFileCompiler.Run(res);
                }
                else
                {
                    res.Serialize();
                }
                resources[hostapp.Name].Add(res.Offset, res);

            }
        }
      
    }
}